﻿#region Copyright(C) 2018 FI Ltd. All rights reserved.
// ==================================================================================================
// Copyright(C) 2018 FI Ltd. All rights reserved.
//
// SYSTEM NAME      : FI.Net Application Framework
// COMPONENT ID     : FI.Core.EntLib
// COMPONENT DESC   : Microsoft Enterprise Library Adapter.
//
// CREATED DATE/BY  : 18 Dec 2018 / Tian Mi
//
// REVISION HISTORY :
// DATE/BY            SR#/CS/PM#/OTHERS       DESCRIPTION OF CHANGE
// ==================================================================================================
#endregion

using FI.Core.EntLib.Properties;
using Microsoft.Practices.ObjectBuilder2;
using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.Configuration;
using Microsoft.Practices.Unity.Configuration.ConfigurationHelpers;
using Microsoft.Practices.Unity.InterceptionExtension;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;


namespace FI.Core.IoC.Configuration
{
    /// <summary>
    /// The <see cref="ContainerConfiguringElement"/> for automatic interception extension.
    /// </summary>
    public class AutoInterceptionElement : ContainerConfiguringElement
    {
        private const string intrceptorProperty = "interceptor";

        /// <summary>
        /// Gets or sets the interceptor.
        /// </summary>
        /// <value>
        /// The interceptor.
        /// </value>
        [ConfigurationProperty(intrceptorProperty, IsRequired = false)]
        public AutoInterceptorElement Interceptor
        {
            get { return (AutoInterceptorElement)this[intrceptorProperty]; }
            set { this[intrceptorProperty] = value; }
        }

        /// <summary>
        /// Configures the container.
        /// </summary>
        /// <param name="container">The container.</param>
        protected override void ConfigureContainer(IUnityContainer container)
        {
            if (null == this.Interceptor)
            {
                return;
            }
            Type interceptorType = TypeResolver.ResolveType(this.Interceptor.TypeName);
            if (!typeof(IInstanceInterceptor).IsAssignableFrom(interceptorType))
            {
                throw new ConfigurationErrorsException(Resources.ExceptionOnlyInstanceInterceptorBeSupported);
            }
            string builderName = interceptorType.AssemblyQualifiedName;
            IEnumerable<InjectionMember> injectionMembers = this.Interceptor.Injection.SelectMany(element => element.GetInjectionMembers(container, typeof(IInstanceInterceptor), interceptorType, builderName));
            container.RegisterType(typeof(IInstanceInterceptor), interceptorType, builderName, new ContainerControlledLifetimeManager(), injectionMembers.ToArray());
            NamedTypeBuildKey builderKey = new NamedTypeBuildKey(typeof(IInstanceInterceptor), builderName);
            ResolvedAutoInterceptorPolicy interceptorPolicy = new ResolvedAutoInterceptorPolicy(key => container.Resolve<IInstanceInterceptor>(key.Name), builderKey);
            container.RegisterInstance(typeof(AutoInterceptorPolicy), typeof(AutoInterceptorPolicy).AssemblyQualifiedName, interceptorPolicy, new ContainerControlledLifetimeManager());
        }
    }
}